﻿using System;
using System.Data.Common;

namespace Centido.Management.ConsoleManager
{
    /// <summary>
    ///   A console command that adds the specified user to the current domain.
    /// </summary>
    internal class AddUserCommand : Command
    {
        /// <summary>
        ///   The user name parameter.
        /// </summary>
        public const string UserNameParameter = "name";

        /// <summary>
        ///   The user name parameter (short name).
        /// </summary>
        public const string UserNameShortParameter = "n";

        /// <summary>
        ///   The user password parameter.
        /// </summary>
        public const string UserPasswordParameter = "password";

        /// <summary>
        ///   The user password parameter (short name).
        /// </summary>
        public const string UserPasswordShortParameter = "p";

        /// <summary>
        ///   The user display name parameter.
        /// </summary>
        public const string UserDisplayNameParameter = "displayname";

        /// <summary>
        ///   The user display name parameter (short name).
        /// </summary>
        public const string UserDisplayNameShortParameter = "dn";

        /// <summary>
        ///   The user login ability parameter.
        /// </summary>
        public const string CanLoginParameter = "canlogin";

        /// <summary>
        ///   The user login ability parameter (short name).
        /// </summary>
        public const string CanLoginShortParameter = "login";

        /// <summary>
        ///   The user ability to change the schema parameter.
        /// </summary>
        public const string CanChangeSchemaParameter = "canchangeschema";

        /// <summary>
        ///   The user ability to change the schema parameter (short name).
        /// </summary>
        public const string CanChangeSchemaShortParameter = "schema";

        /// <summary>
        ///   The user ability to change security settings parameter.
        /// </summary>
        public const string CanChangeSecurityParameter = "canchangesecurity";

        /// <summary>
        ///   The user ability to change security settings parameter (short name).
        /// </summary>
        public const string CanChangeSecurityShortParameter = "security";


        /// <summary>
        ///   Gets the console command name.
        /// </summary>
        public override string Name
        {
            get { return "adduser"; }
        }


        /// <summary>
        ///   Gets the console command description.
        /// </summary>
        public override string Description
        {
            get { return Messages.AddUserCommandDescription; }
        }


        /// <summary>
        ///   Gets the console command full description.
        /// </summary>
        public override string FullDescription
        {
            get { return Messages.AddUserCommandFullDescription; }
        }


        /// <summary>
        ///   Executes the console command.
        /// </summary>
        /// <param name="context">The console command execution context.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="context"/> is null.</exception>
        public override void Execute(CommandExecutionContext context)
        {
            base.Execute(context);

            if (!CheckCommandParameters(context)) return;

            if (context.CurrentDomain == null) return;

            var domain = context.CurrentDomain;

            // If there is no permission to perform this operation
            if (!domain.CurrentUser.CanChangeSecurity)
            {
                Console.WriteLine(Messages.NeedCanChangeSecurityPermissionMessage);
                return;
            }

            // The user name
            var userName = context.GetParameterValue(UserNameParameter, UserNameShortParameter);
            // The user password
            var userPassword = context.GetParameterValue(UserPasswordParameter, UserNameShortParameter);

            try
            {
                var user = domain.GetUser(userName) ?? domain.AddUser(userName, userPassword);

                // If the display name was specified
                if (context.ParameterValueIsNotEmpty(UserDisplayNameParameter, UserDisplayNameShortParameter))
                    user.DisplayName = context.GetParameterValue(UserDisplayNameParameter, UserDisplayNameShortParameter);

                // If the login ability was specified
                if (context.ParameterValueIsNotEmpty(CanLoginParameter, CanLoginShortParameter))
                {
                    try
                    {
                        user.CanLogon = bool.Parse(context.GetParameterValue(CanLoginParameter, CanLoginShortParameter));
                    }
                    catch (FormatException)
                    {
                        Console.WriteLine(Messages.AddUserCommandCanLoginFormatError);
                        return;
                    }
                }

                // If the ability to change the schema was specified
                if (context.ParameterValueIsNotEmpty(CanChangeSchemaParameter, CanChangeSchemaShortParameter))
                {
                    try
                    {
                        user.CanChangeSchema = bool.Parse(context.GetParameterValue(CanChangeSchemaParameter, CanChangeSchemaShortParameter));
                    }
                    catch (FormatException)
                    {
                        Console.WriteLine(Messages.AddUserCommandCanChangeSchemaFormatError);
                        return;
                    }
                }

                // If the ability to change the security settings was specified
                if (context.ParameterValueIsNotEmpty(CanChangeSecurityParameter, CanChangeSecurityShortParameter))
                {
                    try
                    {
                        user.CanChangeSecurity = bool.Parse(context.GetParameterValue(CanChangeSecurityParameter, CanChangeSecurityShortParameter));
                    }
                    catch (FormatException)
                    {
                        Console.WriteLine(Messages.AddUserCommandCanChangeSecurityFormatError);
                        return;
                    }
                }
            }
            catch (ArgumentException e)
            {
                Console.WriteLine(e.Message);
                Console.WriteLine();
                return;
            }
            catch (DbException e)
            {
                Console.WriteLine(e.Message);
                Console.WriteLine();
                return;
            }
            
            // Displaying the success message
            Console.WriteLine(Messages.CommandCompletedMessage);
        }


        /// <summary>
        ///   Checks the presence of all required command parameters.
        /// </summary>
        /// <param name="context">The console command execution context.</param>
        /// <returns>Returns true if everything is ok; otherwise, returns false.</returns>
        private static bool CheckCommandParameters(CommandExecutionContext context)
        {
            if (!context.ParameterValueIsNotEmpty(UserNameParameter, UserNameShortParameter)
                || !context.ParameterValueIsNotEmpty(UserPasswordParameter, UserPasswordShortParameter))
            {
                Console.WriteLine(Messages.AddUserCommandNotAllParametersSpecifiedMessage);
                return false;
            }

            return true;
        }
    }
}
